General Principles "Nay, but you, who do not love her. Is she not pure gold my mistress." Browning, 1812-1889 The Unit Variables Gold is designed such that with a few lines of code, you can achieve a great deal of functionality. For example, with just a single line of code, you can display a file input dialog box showing files, directories, etc. This simplicity is possible because Gold has a rich set of default properties; for example, the color of the push buttons and the shadow style of windows. If you don't like the defaults, you can change them! Each unit in Gold contains a special record that defines defaults pertinent to the unit. The name of this record follows a standard convention: the name begins with the unique characters in the unit name, and ends with the four characters VARS. For example, the GOLDDIR.PAS unit contains the global variable DIRVARS, the GOLDCAL.PAS unit contains the global variable CALVARS, and the GOLDMENU.PAS unit contains the global variable MENUVARS. And so on. You can modify elements of these records to customize the appearance and behavior of Gold. For example, you can redefine the keystrokes used to navigate a calendar by changing the NextMKey, PrevMKey, NextYKey and PrevYKey elements: CalVars.NextMKey := 360; CalVars.PrevMKey := 361; CalVars.NextYKey := 362; CalVars.PrevYKey := 363; Similarly, the default calculator style can be customized by assigning a value to the CalcVars' element Style, as follows: CalcVars.Style := CalcWide; Throughout the user's guide, references are made to relevant elements of the global variables defined in each unit. Just remember that we have tried to make Gold very flexible and if you're not sure how to customize the properties of a Gold component, look at the appropriate XXXVARS variable in the unit source code, and see whether there is a relevant element that you can customize. A different approach is used for customizing colors. Refer to the section Customizing Display Colors. Compiler Directives and GOLDFLAG.INC Every unit in Gold has an include statement to include the file GOLDFLAG.INC. This file is designed to specify all the common compiler directives that you want to apply to every unit in your program. The compiler directives added to your main program apply only to that module and not to any of the units used by that program. So if you wanted to ensure that a specific compiler directive is operative in every unit, you would have to edit every units source code and add the appropriate directive. Yes, you could add them to the IDE options menu, but if you work on multiple projects, it is a chore making sure that you have the appropriate directives set. The most foolproof way is to set the directives in an include file. Whenever you develop a program using Gold, you should add an include directive to the main program and any other units you develop, as follows: {$I GOLDFLAG.INC} Any compiler directives you set in the file GOLDFLAG.INC will then affect your code and the Gold code. The GOLDFLAG.INC file contains a set of master conditional compiler directives named FINAL, OVERLAY, FLOAT, FLOATEM, NOVGACHARS, CUTANDPASTE, WORDWRAP and TTT5. By enabling or disabling these master directives, you are setting families of specific directives. For example, by enabling the FINAL directive, you are indirectly setting the state of the range checking, stack checking, debug, and linker directives. These master directives are located at the top of GOLDFLAG.INC, and by default, some are enabled and others are disabled. In the disabled state, the $DEFINE directive is broken up with spaces, e.g. { $ DEFINE OVERLAY} To activate a directive, simply remove the leading spaces, e.g. {$DEFINE OVERLAY} Listed below are the default settings of the master compiler directives: { $ DEFINE FINAL} { $ DEFINE FLOAT} { $ DEFINE FLOATEM} { $ DEFINE OVERLAY} { $ DEFINE NOVGACHARS} { $ DEFINE TTT5} {$DEFINE CUTANDPASTE} {$DEFINE WORDWRAP} As the listing shows, all the major directives are disabled, and the two word processing directives are enabled. The purpose of the individual compiler directives are discussed below. FINAL During program development it is a good idea to switch on range checking and stack checking, etc. These directives keep you honest and allow the compiler to quickly identify potential problems. For example, if you try to assign a value of 300 to a byte, the problem will be identified with a range error at run-time. The bad news is that programs compiled in the check everything state tend to be slower and larger than their carefree brethren. So, once you have debugged and tested your program and you are confident that the checking is no longer necessary, you should switch off the appropriate directives. The FINAL compiler directive is designed to simplify this task. During program development, you should disable the FINAL compiler directive, and then enable it when you are ready to build and distribute your production program. IMPORTANT NOTE: If you want to debug your program using the internal or external debugger, you must disable the FINAL directive. When FINAL is disabled, another directive CHECK is defined. When CHECK is enabled, Gold uses some additional code to check that sensible parameters are passed to procedures. For example, in GoldDB checks are made to ensure that the specified Field number exists. FLOAT Gold supports extended reals. By default, Borland Pascal uses 6-byte reals, but using compiler directives, varying precision reals can be used, i.e. Single, Double, Extended and Comp. If you want to use the higher precision reals, enable the FLOAT compiler directive. Gold will automatically set the appropriate compiler directives. When FLOAT is enabled, Gold supports all real types. When FLOAT is disabled, all the real types are type-cast to the base REAL type. In other words, you can still reference the types SINGLE, DOUBLE, EXTENDED and COMP in your code, but they all appear to the compiler as plain old REAL. The type-casting is performed by the small unit GOLDREAL.PAS. If your program is compiled with FLOAT enabled and it is going to be executed on a computer without a math co-processor installed, the FLOATEM compiler directive (discussed next) must also be enabled. Note that the GOLDHARD function MathChip will return true if the system has a match co-processor installed. FLOATEM Borland Pascal is capable of emulating an 8087 math co-processor if the PC does not have one installed. Enable the FLOAT and FLOATEM (short for float emulation) directives if you want to use high precision reals on PCs without a math co-processor. OVERLAY Any of the Gold units can be overlaid. Borland Pascal requires that all overlaid units include the {$O+} compiler directive, and that all procedures and functions are compiled using the far calling method, i.e. they are compiled in the {$F+} state. By activating the OVERLAY directive in GOLDFLAG.INC, all the Gold units will be compiled in the {$F+,$O+} state. To help you create programs with overlays, Gold includes the template file GOLDOVR.PAS. When you need to overlay some Gold units, you should make a copy of GOLDOVR.PAS to a new file, e.g. ACCNTOVR.PAS. Then edit the name of the program overlay file (default: PROGRAM.OVR) to reflect the name of the file which will contain the compiled overlay code, e.g. ACCOUNTS.OVR. The USES statement of the main program must list the AccntOVR file (or whatever name you gave the unit) before the Gold units which are to be overlaid. For example: program AccountsPayable; {ACCOUNTS.PAS} {$F+} USES OVERLAY,DOS,CRT, AccntOVR, GoldFAST, GoldWIN, GoldIO; {$O GoldFAST} {$O GoldWIN} {$O GoldIO} begin {.....} end. In the example, by the time the program tries to load GoldFAST, the overlay manager has already been installed (by AccntOVR) and so the GoldFAST initialization section can be successfully executed as an overlay. Review the demo program DEMOV1.PAS and its accompanying unit DEMOV1UN.PAS to see these techniques in action. NOVGACHARS One of the innovations in Gold is the ability, on VGA systems, to use custom characters for drawing box borders, window icons and the like (see the section Using Custom Characters below). The support for custom characters is woven into the fabric of the GoldFAST unit. If you have no intention of deploying these custom characters in your applications, you can save code and data resources by enabling the NOVGACHARS directive. Obviously, if this directive is enabled, your program won't be able to use the special drawing characters. TTT5 Many Gold developers have existing programs written with TechnoJock's Turbo Toolkit version 5.0. Unfortunately, existing programs cannot simply be ported to Gold by modifying the USES statement to use the Gold units instead of the TTT units. The reason? A number of fundamental changes (i.e. improvements!) were made in the basic toolkit design. For example, all underscores were removed from procedure and function names, and color attributes are passed as a single (combined) byte rather than separate foreground and background attributes. Although we recommend that you change your programs to use the new naming and parameter conventions, we do recognize what a pain this can be! By enabling the TTT5 direction in GOLDFLAG.INC, you can get the best of both worlds, because Gold automatically supports the majority of old-style function calls. For example, with TTT5 enabled, you could call ActivateVisibleScreen or the old-style Activate_Visible_Screen. There is, however, a complication because Borland Pascal does not allow two procedures to have the same name within a unit. In many situations Gold has changed a procedure's parameters but used the same name. For example, Gold WriteAT accepts four parameters: the X,Y coordinate, the combined display attribute, and the string. In TTT 5.0, the same procedure accepted 5 parameters -- the attribute was passed as a foreground and a background byte. Borland Pascal doesn't allow two procedures to be named WriteAT. So, we named the old-style procedure FBWriteAT; solving the naming problem and giving an indication of the main difference between the old-style procedure and its new counterpart. Refer to the GoldDust paper "Porting TTT Applications" if you are trying to port an old TTT application to use Gold. This paper lists all the old TTT 5.0 exported procedures, identifiying the TTT5-directive equivalent along with the Gold equivalent. The GoldMEMO unit provides sophisticated text editing capabilities including cut-and-paste and word-wrap. If you only need a plain text editor, and don't need these features, you can disable the features and reduce the program size by using the CUTANDPASTE and WORDWRAP compiler directives. CUTANDPASTE The CUTANDPASTE directive controls whether Gold will support text cut-and-paste in the editing functions. Disable this directive if you want to use an editor but don't need cut-and-paste; the program will be smaller. WORDWRAP The WORDWRAP directive controls whether Gold will support automatic word-wrapping in the text editing functions. Disable this directive if you want to use an editor but don't need word-wrap; the program will be smaller. Handling Errors Errors happen! As a developer you understand, more than most, that errors can occur while a program is running. Gold will always try to deal with an error in an appropriate way. When a program is compiled with the FINAL directive disabled, Gold will alert you to errors (typically in a PromptOK message), whether they are trivial or mind-blowingly important. However, when the program is compiled with FINAL enabled, the user will not be made aware of the error if the consequence of the error is probably trivia. If the error is profound, (e.g. there is no memory left) a dialog will be displayed to the user. All the Gold units that have the potential to fail at run-time (which is the majority), have a function which can be called to determine whether the last operation was a success. The name of the function is LastXXXError, where XXX is the unique identifier in the unit name, e.g. LastWINError, LastCALCError, etc. If you are writing a commercial-quality application, you should always call these last error functions when there is a chance that the last operation failed. The following example shows how to test for an error in the RunCalendar function: Answer := RunCalendar(TodayInJul,' A Calendar! '); if LastCalError <> 0 then promptOK(' Error ','Unable to display calendar') else begin if CalVars.ChooseDay then begin if Answer = 0 then PromptOK('','You escaped!') else PromptOK('',' You selected ' +FancyDateStr(Answer,false,false)); end; end; Refer to the Gold Reference manual for a complete list of all the LastXXXError functions. ERROR CUSTOMIZATION Most of the Gold units are organized so that international users can replace the English error messages with local language messages. The GoldMisc unit includes the following type declaration: ErrMsgFunc = function (Ecode:integer):string; To use custom error messages, all you need to do is create a far procedure which is declared the same as the ErrMsgFunc defined above. The function is passed an error code and should return a string explaining the nature of the error. The following is an extract of the English error messages in GoldMisc (by way of an example): function MyMiscEMsg(ECode:integer): string; {} begin case Ecode of 1001: MyMiscEMsg := 'Invalid drive.'; 1002: MyMiscEMsg := 'Failure changing directory'; 1003: MyMiscEMsg := 'Failure making directories'; else MyMiscEMsg := 'Internal Misc error'; end; {case} end; { MyMiscEMsg } Having created a far procedure with the custom error messages, you must then instruct Gold to use your function in place of the standard message function. To do this, assign the procedure to the local variable EmsgFunc which is stored in the XXXVARS record (discussed in the first section of this chapter). The following code fragment shows this technique being used to assign custom messages for the GoldMISC unit: MiscVars.EMsgFunc := MyMiscEMsg; Understanding Hooks Good though Gold is, there will be situations where Gold doesn't meet your specific applications needs. In many cases, the XXXVARS structure will provide you with ways to customize Gold. For example, if you want change the window type for the prompt dialogs, you could use the following statement to instruct Gold to use a window style of 1: WinVars.PromptStyle := 1; In sophisticated applications, you might encounter some behavior or characteristic which cannot be readily changed using the above-mentioned technique. Hey, we can't think of everything! The solution to these truly custom needs lies in user-defined hooks which interact with low-level internal routines. A hook is a procedure or function which is called at strategic times during the execution of an application. For example, a user-defined hook can be called every time a user tries to leave an input field in a form. Another example is a hook that is called every time a user changes selections on a menu. In simple terms, a hook is a user-defined procedure which is called by Gold whenever a specific event occurs. But a hook goes beyond a simple notification event; a hook can actually change the program behavior. For example, a form EnterFieldHook can redirect focus (i.e. the highlighted field) to a different field, and a character hook can replace the character Alt-A with the five characters "APPLE". There are over 30 hooks scattered about the product. If you find that a particular unit does not behave just how you would like, review the Hook section in the appropriate chapter and see if a hook will allow you to customize Gold's behavior. CREATING A HOOK ROUTINE To take advantage of a hook, you must create a procedure or function with the exact declaration of the hook. In other words, the routine must be declared with the exact number and type of passed parameters, and (in the case of function hooks) the function must return the correct type. Refer to the specific documentation for a clarification of each hook's declaration. You must create the procedure or function at the root level of a program or unit, i.e. it must not be nested within a parent procedure or function. The procedure must be declared as a far procedure. You can do this by adding the far keyword on the procedure declaration line, or by using the {$F+} compiler directive. The following hook is extracted from the demo program DEMIO6.PAS and shows a hind hook being used in an IO form to control whether field number 10 is enabled or disabled: {$F+} procedure MyHindHook(CurrentField:byte;var Refresh:byte); {} begin Refresh := RefreshNone; if CurrentField = 9 then {radio button} begin if (Cust.Radio = 4) and (FieldGetState(10) = FldOn) then begin FieldSetState(10,FldOff); Refresh := RefreshOthers; end else if (Cust.Radio <> 4) and not (FieldGetState(10) = FldOn) then begin FieldSetState(10,FldOn); Refresh := RefreshOthers; end; end; end; {MyHindHook} {$F-} INSTALLING & REMOVING A HOOK Having created the hook procedure or function, you must instruct Gold to call the routine when the hook event occurs. Refer to the hook documentation in the appropriate chapter to determine how to install and remove hooks. In most cases, Gold provides Assign... and Remove... procedures for installing and removing hooks. For example, the following statement instructs Gold to use the MyHindHook procedure (defined above) to the IO hind hook: AssignHindHook(MyHindHook); If there is no Remove function, just assign the default hook, for example: AssignHindHook(NoHindHook); Customizing Display Colors Colors, colors, colors. We get more calls about colors than anything. One person's ideal color is another person's anathema. If only PCs used green CRT tubes! We have finally realized that we cannot please everybody with our default colors. The next best thing is to make it easy for you to customize the colors to meet your own needs. The GoldTINT unit is designed to make it very easy for you to customize the default colors used in Gold. This unit provides a global variable named TINT which defines every color used in Gold. You can change a color using the procedure GoldSetColor which is defined as follows: GoldSetColor(Zone:TintElement; Col:byte); The first parameter identifies the TintElement (see Table 3.1), and the second attribute is the color byte. Use the function GoldGetColor to determine the active color for a specific tint element. Gold uses a single byte to define the foreground and background colors. Table 3.2 (below) identifies all the supported color codes. Table 3.2 Color Codes Blk Blu Grn Cyn Red Mgt Brn Black 0 16 32 48 64 80 96 Blue 1 17 33 49 65 81 97 Green 2 18 34 50 66 82 98 Cyan 3 19 35 51 67 83 99 Red 4 20 36 52 68 84 100 Magenta 5 21 37 53 69 85 101 Brown 6 22 38 54 70 86 102 Lt. Gray 7 23 39 55 71 87 103 Dark Gray 8 24 40 56 72 88 104 Lt. Blue 9 25 41 57 73 89 105 Lt. Green 10 26 42 58 74 90 106 Lt. Cyan 11 27 43 59 75 92 107 Lt. Red 12 28 44 60 76 92 108 Lt. Magenta 13 29 45 61 77 93 109 Yellow 14 30 46 62 78 94 110 White 15 31 47 63 79 95 111 Lt. Dk. Lt. Lt. Lt. Lt. Lt. Gry Gry Blu Grn Cyn Red Mgt Yel Wht Black 112 128 144 160 176 192 208 224 240 Blue 113 129 145 161 177 193 209 225 241 Green 114 130 146 162 178 194 210 226 242 Cyan 115 131 147 163 179 195 211 227 243 Red 116 132 148 164 180 196 212 228 244 Magenta 117 133 149 165 181 197 213 229 245 Brown 118 134 150 166 182 198 214 230 246 Lt. Gray 119 135 151 167 183 199 215 231 247 Dark Gray 120 136 152 168 184 200 216 232 248 Lt. Blue 121 137 153 169 185 201 217 233 249 Lt. Green 122 138 154 170 186 202 218 234 250 Lt. Cyan 123 139 155 171 187 203 219 235 251 Lt. Red 124 140 156 172 188 204 220 236 252 Lt. Magenta 125 141 157 173 189 205 221 237 253 Yellow 126 142 158 174 190 206 222 238 254 White 127 143 159 175 191 207 223 239 255 The following example sets the display color of prompt titles (in the PromptOK dialogs) to yellow on red: GoldSetColor(PromptTitle,78); The GoldATTR unit includes a couple of features which help you assign new colors without having to look up values in Table 3.2. The unit includes 256 constants which correspond with all the possible color combinations. For example, the constant YellowOnRed has the value 78 ($4E in hex), and so by including GoldATTR in the uses clause, the above example could be simplified to the following: GoldSetColor(PromptTitle,YellowOnRed); The GoldATTR unit also includes the following procedures and functions to assist in handling foreground and background display attributes: CAttr(F,B:byte):byte; Accepts separate foreground and background attributes, and returns the combined attribute byte. FAttr(A:byte): byte; Accepts a combined attribute byte, and returns the foreground color. BAttr(A:byte): byte; Accepts a combined attribute byte, and returns the background color. Blinking Colors On VGA systems, you can use the SetBlinking procedure to control whether light background colors are displayed with a normal, bright background, or as blinking characters on a dark color background. When SetBlinking is passed a TRUE value, bright/light background colors will cause the foreground colors to blink. Note that there is a hardware limitation; the blinking state applies to the entire display, not to an individual write statement. In other words, you cannot have some text with blinking characters in one portion of the display, and some other text with bright background colors in a different part of the display. Using Custom Characters On VGA (or better) display systems, Gold uses a technique for drawing custom characters to give check boxes, radio buttons and windows a special graphical appearance. You can test whether the display system supports the custom characters by calling the function CustomCapable. The function returns TRUE if the custom characters are supported, otherwise FALSE is returned. By default, the normal ASCII character set is used. You can enable the custom drawing characters by calling the procedure UseCustomChars. Behind the scenes, Gold replaces the double-line drawing characters with a set of custom characters. So, if you are using the custom characters, you sacrifice the double line characters. Run the demo program DEMCUST1.PAS to see the character substitution. If, having called UseCustomChars, you do not get the special drawing characters, check that the conditional compiler directive NOVGACHARS (discussed earlier in this chapter) is not enabled. Once you have enabled the custom characters, you do not need to explicitly build your own boxes and buttons using these characters. Gold will automatically apply the new characters to windows, etc. provided you have selected a window style that uses these characters. See the demo program DEMWIN1.PAS for an example of these styles. You can write an application which takes full advantage of custom characters (such as the Gold installation program), and not have to worry about how the application will behave on systems which do not support these characters. Gold automatically changes the display characters so that the application looks professional on non-custom character capable systems. In addition to the standard custom drawing characters, Gold offers a special character set for drawing the 12 functions keys. Call the procedure UseCustomFunctionKeys to activate these custom characters. Call the procedure RemoveCustomChars to remove the custom character set and reinstate the double-line characters.